package be.ac.info.fundp.TVLParser.SyntaxTree;

import java.util.Vector;

import be.ac.info.fundp.TVLParser.Util.Util;
import be.ac.info.fundp.TVLParser.exceptions.AmbiguousReferenceException;
import be.ac.info.fundp.TVLParser.exceptions.BadTypeUseException;
import be.ac.info.fundp.TVLParser.exceptions.ChildrenFeatureNotFoundException;
import be.ac.info.fundp.TVLParser.exceptions.ExpressionOutOfBoundException;
import be.ac.info.fundp.TVLParser.exceptions.ExpressionTypeViolatingAttributeTypeException;
import be.ac.info.fundp.TVLParser.exceptions.IDEnumValuesConflictException;
import be.ac.info.fundp.TVLParser.exceptions.IllegalExpressionException;
import be.ac.info.fundp.TVLParser.exceptions.SetExpressionMemberOutOfBoundException;
import be.ac.info.fundp.TVLParser.exceptions.SetExpressionMemberViolatingAttributeTypeException;
import be.ac.info.fundp.TVLParser.exceptions.SharedFeatureUsingParentConstructorException;
import be.ac.info.fundp.TVLParser.exceptions.SharedFeatureUsingParentSelectorException;
import be.ac.info.fundp.TVLParser.exceptions.SymbolNotFoundException;
import be.ac.info.fundp.TVLParser.symbolTables.AttributeSymbol;


public class AndAggExpression implements BooleanExpression {
	
	ExpressionList expressionList;
	ChildrenAttributeID childrenAttributeID;
	
	public AndAggExpression(ExpressionList e1) {
		this.expressionList = e1;
	}
	
	public AndAggExpression(ChildrenAttributeID e1) {
		this.childrenAttributeID = e1;
	}

	/**
	 * @return the expressionList
	 */
	public ExpressionList getExpressionList() {
		return expressionList;
	}

	/**
	 * @return the childrenAttributeID
	 */
	public ChildrenAttributeID getChildrenAttributeID() {
		return childrenAttributeID;
	}
	
	public String toString() {
		if (this.expressionList != null) {
			return "and( "+this.expressionList.toString()+" )";
		}
		else
			return "and( "+this.childrenAttributeID.toString()+" )";
	}

	public int getType() throws AmbiguousReferenceException, SymbolNotFoundException, IllegalExpressionException, SharedFeatureUsingParentConstructorException, BadTypeUseException, SharedFeatureUsingParentSelectorException, ChildrenFeatureNotFoundException, IDEnumValuesConflictException, NumberFormatException, SetExpressionMemberOutOfBoundException, SetExpressionMemberViolatingAttributeTypeException, ExpressionTypeViolatingAttributeTypeException, ExpressionOutOfBoundException {
		if (this.expressionList == null) {
			if (this.childrenAttributeID.getType() == Expression.BOOL)
				return Expression.BOOL;
			else
				throw new IllegalExpressionException("Type error : the expression "+this.toString()+" is invalid. In an aggregate and expression, the type of the parameter must be bool. Currently, The type of the children attribute is "+Util.toStringExpressionType(this.childrenAttributeID.getType())+" and not bool");
		}
		else {
			if (this.expressionList.getType() == Expression.BOOL)
				return Expression.BOOL;
			else
				throw new IllegalExpressionException("Type error : the expression "+this.toString()+" is invalid. In an aggregate and expression, the type of the parameter must be bool. Currently, The type of the expression list is "+Util.toStringExpressionType(this.childrenAttributeID.getType())+" and not bool");
		}
	}
	
	public Expression toNormalForm() {
		if (this.childrenAttributeID != null) {
			if (this.childrenAttributeID.selectionType == ChildrenAttributeID.SELECTED_CHILDREN) {
				Vector<Object> childrenAttributesPath = this.childrenAttributeID.getChildrenAttributesPath();
				QuestExpression questExpression = new QuestExpression(new LongIDExpression(childrenAttributesPath.get(0).toString(), null), new LongIDExpression(childrenAttributesPath.get(0).toString()+"."+((AttributeSymbol) childrenAttributesPath.get(1)).getID(), null),new TrueExpression());
				ExpressionList expressionList =  new ExpressionList(questExpression);
				int i =2;
				while (i <= childrenAttributesPath.size()-1) {
					questExpression = new QuestExpression(new LongIDExpression(childrenAttributesPath.get(i).toString(), null), new LongIDExpression(childrenAttributesPath.get(i).toString()+"."+((AttributeSymbol) childrenAttributesPath.get(i+1)).getID(), null),new TrueExpression());
					expressionList =  new ExpressionList(questExpression, expressionList);
					i = i + 2;
				}
				return new AndAggExpression(expressionList);
			}
			else {
				Vector<Object> childrenAttributesPath = this.childrenAttributeID.getChildrenAttributesPath();
				LongIDExpression longIDExpression = new LongIDExpression(childrenAttributesPath.get(0).toString()+"."+((AttributeSymbol) childrenAttributesPath.get(1)).getID(), null);
				ExpressionList expressionList =  new ExpressionList(longIDExpression);
				int i =2;
				while (i <= childrenAttributesPath.size()-1) {
					longIDExpression = new LongIDExpression(childrenAttributesPath.get(i).toString()+"."+((AttributeSymbol) childrenAttributesPath.get(i+1)).getID(), null);
					expressionList =  new ExpressionList(longIDExpression, expressionList);
					i = i + 2;
				}
				return new AndAggExpression(expressionList);
			}
		}
		else {
			int i =0;
			ExpressionList normalizedExpressionList =  new ExpressionList(this.expressionList.getExpressions().get(i).toNormalForm());
			i = 1;
			while (i <= this.expressionList.expressions.size()-1) {
				normalizedExpressionList = new ExpressionList(this.expressionList.getExpressions().get(i).toNormalForm(), normalizedExpressionList);
				i++;
			}
			return new AndAggExpression(normalizedExpressionList);
		}
	}
	 
	public BooleanExpression toSimplifiedForm() {
		 if (this.expressionList.expressions.size() != 1) {
			AndExpression simplifiedExpression = new AndExpression(((BooleanExpression) this.expressionList.expressions.get(0)).toSimplifiedForm(), ((BooleanExpression)  this.expressionList.expressions.get(1)).toSimplifiedForm());
			int i = 2;
			while (i <= this.expressionList.expressions.size()-1) {
				simplifiedExpression = new AndExpression(simplifiedExpression, ((BooleanExpression) this.expressionList.expressions.get(i)).toSimplifiedForm());
				i++;
			}
			return new ParenthesesExpression(simplifiedExpression);
		 }
		 else {
			return ((BooleanExpression) this.expressionList.expressions.get(0)).toSimplifiedForm();
		 }
	 }
	
	/** This method is normally never used because the toSimplifiedForm() method removes each XorAggExpression from the diagram.
	 * 
	 * @return
	 */
	public BooleanExpression removeArrows() {
		return this;
	}
	
	/** This method is normally never used because the toSimplifiedForm() method removes each XorAggExpression from the diagram.
	 * 
	 * @return
	 */
	public BooleanExpression distributeDisjunctions() {
		return this;
	}

	/** This method is normally never used because the toSimplifiedForm() method removes each XorAggExpression from the diagram.
	 * 
	 * @return
	 */
	public BooleanExpression distributeNegations() {
		return this;
	}
}